using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UObject = UnityEngine.Object;

public class ResourcesManager : MonoBehaviour
{
    //文件信息类
    internal class BundleInfo
    { 
        public string assetName;
        public string bundleName;
        public List<string> dependences;
    }

    internal class BundleData
    {
        public AssetBundle bundle;

        //引用计数，计数为零时说明该bundle没有被使用，此时便可以卸载该资源
        public int count;

        public BundleData(AssetBundle ab)
        {
            bundle = ab;
            count = 1;
        }
    }

    //用于存放bundle信息
    private Dictionary<string, BundleInfo> bundleInfoDic = new Dictionary<string, BundleInfo>();

    //缓存已经加载的bundle资源
    private Dictionary<string, BundleData> assetBundleDic = new Dictionary<string, BundleData>();

    /// <summary>
    /// 解析版本文件
    /// </summary>
    public void ParseVersionFile()
    {
        //版本文件路径
        string url = Path.Combine(PathUtil.BundleResourcePath, AppConst.FileListName);

        //读取版本文件内容
        string[] data = File.ReadAllLines(url);

        //解析文件信息
        for (int i = 0; i < data.Length; i++)
        {
            BundleInfo bundleInfo = new BundleInfo();
            string[] info = data[i].Split('|');

            bundleInfo.assetName = info[0];
            bundleInfo.bundleName = info[1];
            bundleInfo.dependences = new List<string>(info.Length - 2);
            for(int j = 2; j < info.Length; j++) 
            {
                //Debug.Log(info[j]);
                bundleInfo.dependences.Add(info[j]);
            }

            bundleInfoDic.Add(bundleInfo.assetName, bundleInfo);

            if (info[0].IndexOf("LuaScripts") > 0)
            {
                Manager.Lua.luaFileNmaes.Add(info[0]);
            }
        }
    }

    #region 资源加载模块

    //加载UI
    public void LoadUI(string _assetName, Action<UObject> action = null)
    {
        LoadAsset(PathUtil.GetUIPath(_assetName), action);
    }

    //加载Lua脚本
    public void LoadLua(string _assetName, Action<UObject> action = null) 
    {
        LoadAsset((_assetName), action);
    }

    //加载模型预制体
    public void LoadModelPrefab(string _assetName, Action<UObject> action =null)
    {
        LoadAsset((_assetName), action);
    }

    //加载场景
    public void LoadScene(string _assetName, Action<UObject> action = null)
    {
        LoadAsset(PathUtil.GetScenePath(_assetName), action);
    }

    //加载音乐（BGM）
    public void LoadMusic(string _assetName, Action<UObject> action = null)
    {
        LoadAsset(PathUtil.GetMusicPath(_assetName), action);
    }

    //加载音效
    public void LoadSoundEffect(string _assetName, Action<UObject> action = null)
    {
        LoadAsset(PathUtil.GetSoundEffectPath(_assetName), action);
    }

    private void LoadAsset(string _assetName, Action<UObject> action = null)
    {
        #if UNITY_EDITOR
        if(AppConst.GameMode == GameMode.EditorMode)
            EditorLoadAsset(_assetName, action);
        else
        #endif
        StartCoroutine(LoadBundleAsync(_assetName, action));
    }

    /// <summary>
    /// 异步加载获取Bundle资源，在加载完成后回调Action返回加载成功的资源
    /// </summary>
    /// <param name="_assetName">资源名</param>
    /// <param name="action">回调信息</param>
    /// <returns></returns>
    IEnumerator LoadBundleAsync(string _assetName, Action<UObject> action = null)
    {
        //获取bundle资源路径
        string bundleName = bundleInfoDic[_assetName].bundleName;
        string bundlePath = Path.Combine(PathUtil.BundleResourcePath, bundleName);

        //递归加载获取所有依赖项
        List<string> dependences = bundleInfoDic[_assetName].dependences;

        //尝试从已经加载的bundle列表中获取对应bundle，获取失败则进行加载
        BundleData bundleData = GetAssetBundle(bundleName);

        //bundle为空说明获取失败，加载对应bundle
        if (bundleData == null)
        {
            //从对象池中获取
            UObject obj = Manager.Pool.Spwan("AssetBundle", bundleName);
            if(obj != null)
            {
                AssetBundle ab = obj as AssetBundle;
                bundleData = new BundleData(ab);
            }
            else
            {
                AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundlePath);
                yield return request;
                bundleData = new BundleData(request.assetBundle);
            }

            assetBundleDic.Add(bundleName, bundleData);
        }

        if (dependences != null && dependences.Count > 0)
        {
            for (int i = 0; i < dependences.Count; i++)
            {
                yield return LoadBundleAsync(dependences[i]);
            }
        }

        if (_assetName.EndsWith(".unity"))
        {
            action?.Invoke(null);
            yield break;
        }

        if(action == null)
        {
            yield break;
        }

        AssetBundleRequest bundleRequest = bundleData.bundle.LoadAssetAsync(_assetName);
        yield return bundleRequest;

        if(action != null && bundleRequest != null)
        {
            action.Invoke(bundleRequest.asset);
        }
    }

    private BundleData GetAssetBundle(string _assetName) 
    {
        BundleData assetBundle = null;

        if(assetBundleDic.TryGetValue(_assetName, out assetBundle))
        {
            assetBundle.count++;
            return assetBundle;
        }
        else
            return null;
    }

    /// <summary>
    /// 编辑器环境加载资源
    /// </summary>
    /// <param name="_assetName"></param>
    /// <param name="action"></param>
    #if UNITY_EDITOR
    private void EditorLoadAsset(string _assetName, Action<UObject> action = null) 
    {
        UObject obj = UnityEditor.AssetDatabase.LoadAssetAtPath(_assetName, typeof(UObject));
        if (obj == null)
            Debug.LogError("assetName is not exist:" + _assetName);

        action?.Invoke(obj);
    }
#endif

    #endregion


    #region 资源卸载模块

    //减去bundle和依赖的引用计数
    public void MinusBundleCount(string assetName)
    {
        string bundleName = bundleInfoDic[assetName].bundleName;

        MinusOneBundleCount(assetName);

        List<string> dependences = bundleInfoDic[assetName].dependences;
        if(dependences != null)
        {
            foreach (var dependence in dependences)
            {
                string name = bundleInfoDic[dependence].bundleName;
                MinusOneBundleCount(dependence);
            } 
        }
    }

    private void MinusOneBundleCount(string bundleName)
    {
        if(assetBundleDic.TryGetValue(bundleName, out BundleData assetBundle))
        {
            if(assetBundle.count > 0)
            {
                assetBundle.count--;
            }

            if(assetBundle.count <= 0)
            {
                Manager.Pool.UnSpwan("AssetBundle", bundleName, assetBundle.bundle);
                assetBundleDic.Remove(bundleName);
            }
        }
    }

    public void UnLoadBundle(UObject obj)
    {
        AssetBundle ab = obj as AssetBundle;

        ab.Unload(true);
    }
    #endregion

    //private void Start()
    //{
    //    ParseVersionFile();
    //    Debug.Log("OK");
    //    LoadUI("TestUI", OnCompleted);
    //}

    //private void OnCompleted(UObject obj)
    //{
    //    GameObject go = Instantiate(obj) as GameObject;
    //    go.transform.SetParent(this.transform);
    //    go.SetActive(true);
    //    go.transform.localPosition = Vector3.zero;
    //    go.transform.localScale = Vector3.one;
    //}
}
